// Copyright (C) 2025, ZWSOFT Co., LTD.(Guangzhou)
// Licensed under the MIT License. See LICENSE in the project root for license information.

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.IO;
using TestClient.Domain;
using TestClient.ViewModel.Util;

namespace TestClient.ViewModel;
public partial class DbTestViewModel : PageViewModelBase
{
    [ObservableProperty]
    private string targetDatabasePath = "";

    public IAsyncRelayCommand GenerateAndEmbedCommand { get; }
    public IAsyncRelayCommand LoadAndWriteCommand { get; }

    public DbTestViewModel(VFAdapterWrapper wrapper, ISnackNotifyService notifyService) : base(wrapper, notifyService)
    {
        GenerateAndEmbedCommand = CreateAsyncRpcCommand(GenerateAndEmbed);
        LoadAndWriteCommand = CreateAsyncRpcCommand(LoadAndWrite);
    }

    private async Task GenerateAndEmbed()
    {
        EnsureConnected();
        // generate base db
        var sourceDb = await Task.Run(GenerateTestDatabase);
        await Task.Run(() =>
        {
            Wrapper.DataTableSave(sourceDb);
        });
    }

    private async Task LoadAndWrite()
    {
        EnsureConnected();
        if (string.IsNullOrWhiteSpace(TargetDatabasePath)) { return; }
        await Task.Run(() =>
        {
            Wrapper.DataTableRetrieve(TargetDatabasePath);
        });
    }

    [RelayCommand]
    private async Task GenerateDbTypeA()
    {
        TargetDatabasePath = await Task.Run(GenerateTestTargetA);
    }
    [RelayCommand]
    private async Task GenerateDbTypeB()
    {
        TargetDatabasePath = await Task.Run(GenerateTestTargetB);
    }
    [RelayCommand]
    private async Task GenerateDbTypeC()
    {
        TargetDatabasePath = await Task.Run(GenerateTestTargetC);
    }
    [RelayCommand]
    private async Task GenerateDbTypeD()
    {
        TargetDatabasePath = await Task.Run(GenerateTestTargetD);
    }
    [RelayCommand]
    private async Task GenerateDbTypeE()
    {
        TargetDatabasePath = await Task.Run(GenerateTestTargetE);
    }
    [RelayCommand]
    private async Task SelectDbFile()
    {
        var path = await Task.Run(() => DialogUtil.ShowOpenFileDialog("", "*.db3", "SQLite|*.db;*.db3;*.sqlite;*.sqlite3;"));
        TargetDatabasePath = path ?? TargetDatabasePath;
    }

    private static string GenerateTestDatabase()
    {
        var sourceDbDefinition = new DatabaseDefinition
        {
            Tables = [
                new() {
                    Name = "Users",
                    Columns =
                    [
                        new () { Name = "Id", DataType = "INTEGER", IsPrimaryKey = true },
                        new () { Name = "Name", DataType = "TEXT", IsNotNull = true },
                        new () { Name = "Email", DataType = "TEXT" }
                    ],
                    Rows =
                    [
                        new Dictionary<string, object?> { { "Id", 1 }, { "Name", "Alice" }, { "Email", "alice@example.com" } },
                        new Dictionary<string, object?> { { "Id", 2 }, { "Name", "Bob" }, { "Email", null } }
                    ]
                },
                new ()
                {
                    Name = "Products",
                    Columns =
                    [
                        new () { Name = "Sku", DataType = "TEXT", IsPrimaryKey = true },
                        new () { Name = "Price", DataType = "REAL", IsNotNull = true },
                        new () { Name = "Stock", DataType = "INTEGER", DefaultValue = 0 }
                    ],
                    Rows =
                    [
                        new Dictionary<string, object> { { "Sku", "A-001" }, { "Price", 19.99 } },
                        new Dictionary<string, object> { { "Sku", "B-002" }, { "Price", 100.50 }, { "Stock", 50 } }
                    ]
                }
            ]
        };
        string tempSourceDbPath = GenerateTimestampedDb3FileName();
        DatabaseGenerator.Generate(sourceDbDefinition, tempSourceDbPath);

        return tempSourceDbPath;
    }

    private static string GenerateTestTargetA()
    {
        var dbDefinition = new DatabaseDefinition
        {
            Tables = [
                new() {
                    Name = "Users",
                    Columns =
                    [
                        new () { Name = "Id", DataType = "INTEGER", IsPrimaryKey = true },
                        new () { Name = "Name", DataType = "TEXT", IsNotNull = true },
                        new () { Name = "Email", DataType = "TEXT" }
                    ],
                    Rows = [ ]
                },
                new ()
                {
                    Name = "Products",
                    Columns =
                    [
                        new () { Name = "Sku", DataType = "TEXT", IsPrimaryKey = true },
                        new () { Name = "Price", DataType = "REAL", IsNotNull = true },
                        new () { Name = "Stock", DataType = "INTEGER", DefaultValue = 0 }
                    ],
                    Rows = [ ]
                },
            ]
        };
        string tempSourceDbPath = GenerateTimestampedDb3FileName();
        DatabaseGenerator.Generate(dbDefinition, tempSourceDbPath);

        return tempSourceDbPath;
    }
    private static string GenerateTestTargetB()
    {
        var dbDefinition = new DatabaseDefinition
        {
            Tables = [
                new() {
                    Name = "Users",
                    Columns =
                    [
                        new () { Name = "Id", DataType = "INTEGER", IsPrimaryKey = true },
                        new () { Name = "Name", DataType = "TEXT", IsNotNull = true },
                        new () { Name = "Email", DataType = "TEXT" }
                    ],
                    Rows = [ ]
                },
            ]
        };
        string tempSourceDbPath = GenerateTimestampedDb3FileName();
        DatabaseGenerator.Generate(dbDefinition, tempSourceDbPath);

        return tempSourceDbPath;
    }
    private static string GenerateTestTargetC()
    {
        var dbDefinition = new DatabaseDefinition
        {
            Tables = [
                new() {
                    Name = "Users",
                    Columns =
                    [
                        new () { Name = "Id", DataType = "INTEGER", IsPrimaryKey = true },
                        new () { Name = "Name", DataType = "TEXT", IsNotNull = true },
                        new () { Name = "Email", DataType = "TEXT" }
                    ],
                    Rows = [ ]
                },
                new ()
                {
                    Name = "Products",
                    Columns =
                    [
                        new () { Name = "Sku", DataType = "TEXT", IsPrimaryKey = true },
                        new () { Name = "Price", DataType = "REAL", IsNotNull = true },
                        new () { Name = "Stock", DataType = "INTEGER", DefaultValue = 0 }
                    ],
                    Rows = [ ]
                },
                new()
                {
                    Name = "Customers",
                    Columns =
                    [
                        new(){Name="Id",DataType="INTEGER",IsPrimaryKey=true}
                    ],
                },
            ]
        };
        string tempSourceDbPath = GenerateTimestampedDb3FileName();
        DatabaseGenerator.Generate(dbDefinition, tempSourceDbPath);

        return tempSourceDbPath;
    }
    private static string GenerateTestTargetD()
    {
        var dbDefinition = new DatabaseDefinition
        {
            Tables = [
                new() {
                    Name = "Users",
                    Columns =
                    [
                        new () { Name = "Id", DataType = "INTEGER", IsPrimaryKey = true },
                        new () { Name = "Name", DataType = "TEXT", IsNotNull = true },
                        new () { Name = "Email", DataType = "TEXT" },
                        new () { Name = "Foo", DataType="INTEGER", DefaultValue=0},
                    ],
                    Rows = [ ]
                },
                new ()
                {
                    Name = "Products",
                    Columns =
                    [
                        new () { Name = "Sku", DataType = "TEXT", IsPrimaryKey = true },
                        new () { Name = "Price", DataType = "REAL", IsNotNull = true },
                        new () { Name = "Stock", DataType = "INTEGER", DefaultValue = 0 }
                    ],
                    Rows = [ ]
                },
            ]
        };
        string tempSourceDbPath = GenerateTimestampedDb3FileName();
        DatabaseGenerator.Generate(dbDefinition, tempSourceDbPath);

        return tempSourceDbPath;
    }
    private static string GenerateTestTargetE()
    {
        var dbDefinition = new DatabaseDefinition
        {
            Tables = [
                new() {
                    Name = "Users",
                    Columns =
                    [
                        new () { Name = "Id", DataType = "INTEGER", IsPrimaryKey = true },
                        new () { Name = "Name", DataType = "TEXT", IsNotNull = true },
                    ],
                    Rows = [ ]
                },
                new ()
                {
                    Name = "Products",
                    Columns =
                    [
                        new () { Name = "Sku", DataType = "TEXT", IsPrimaryKey = true },
                        new () { Name = "Price", DataType = "REAL", IsNotNull = true },
                        new () { Name = "Stock", DataType = "INTEGER", DefaultValue = 0 }
                    ],
                    Rows = [ ]
                },
            ]
        };
        string tempSourceDbPath = GenerateTimestampedDb3FileName();
        DatabaseGenerator.Generate(dbDefinition, tempSourceDbPath);

        return tempSourceDbPath;
    }

    private static string GenerateTimestampedDb3FileName(string prefix = "temp_")
    {
        string tempDirectory = Path.GetTempPath();

        string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
        string randomPart = Path.GetRandomFileName().Substring(0, 4);

        string fileName = $"{prefix}{timestamp}_{randomPart}.db3";
        return Path.Combine(tempDirectory, fileName);
    }
}
